﻿/**
 * @file ut_point.h
 * @author 贺亚猛
 * @brief  此文件用来实现系统所需的全部点结构，
 *         并且封装点相关的全部算法
 * @version 0.1
 * @date 2022-02-08
 * @copyright Copyright 2022 Langge Software Co., Ltd. All rights reserved.
 */
#ifndef UT_POINT_H
#define UT_POINT_H

#include "ut_symbols.h"
#include "ut_math.h"
#include <stdint.h>
#include <cmath>

BEGIN_SPACE_LANGE_VDR

/**
 * @brief 实现二维点结构，并且封装二维点相关
 *        的全部算法
 * @tparam T  定义内部数据类型
 */
template<typename T>
class UT_API UT2DPoint
{
public:
    UT2DPoint();
    UT2DPoint(const T x,const T y);
    UT2DPoint(const UT2DPoint &src);
    ~UT2DPoint();
public:
    void SetX(const T x);
    T GetX() const;
    void SetY(const T y);
    T GetY() const;
    void Offset(const T x,const T y);
    void Offset(const UT2DPoint &off);
    T CalculateDistance(const T x,const T y) const;
    T CalculateDistance(const UT2DPoint &pt) const;
    T CalculateSquareDistance(const T x,const T y,const T rate=static_cast<T>(1));
    T CalculateSquareDistance(const UT2DPoint &pt,const T rate=static_cast<T>(1));
public:
    UT2DPoint &operator=(const UT2DPoint &src);
    bool operator==(const UT2DPoint &pt) const;
    bool operator!=(const UT2DPoint &pt) const;
    UT2DPoint operator+(const UT2DPoint &pt) const;
    UT2DPoint &operator+=(const UT2DPoint &pt);
    UT2DPoint operator-(const UT2DPoint &pt) const;
    UT2DPoint &operator-=(const UT2DPoint &pt);
private:
    T m_tX;
    T m_tY;
};

/**
 * @brief 构造函数
 * @tparam T   数据类型
 */
template<typename T>
UT2DPoint<T>::UT2DPoint()
    :m_tX(static_cast<T>(0))
    ,m_tY(static_cast<T>(0))
{
}

/**
 * @brief 构造函数
 * @tparam T    数据类型
 * @param  x    x分量 
 * @param  y    y分量
 */
template<typename T>
UT2DPoint<T>::UT2DPoint(const T x,const T y)
    :m_tX(x)
    ,m_tY(y)
{
}

/**
 * @brief  拷贝构造函数
 * @tparam T       数据类型     
 * @param  src     拷贝源
 */
template<typename T>
UT2DPoint<T>::UT2DPoint(const UT2DPoint &src)
    :m_tX(src.m_tX)
    ,m_tY(src.m_tY)
{
}

/**
 * @brief 析构函数
 * @tparam T   数据类型
 */
template<typename T>
UT2DPoint<T>::~UT2DPoint()
{
}

/**
 * @brief 重载赋值操作符
 * @tparam T     数据类型 
 * @param  src   拷贝源 
 * @return 返回自身引用 
 */
template<typename T>
UT2DPoint<T> &UT2DPoint<T>::operator=(const UT2DPoint &src)
{
    if(&src!=this)
    {
        m_tX=src.m_tX;
        m_tY=src.m_tY;
    }
    return *this;
}

/**
 * @brief 检测当前点与指定点是否相同
 * @tparam T       数据类型
 * @param  pt      指定点 
 * @return true    相同
 * @return false   不同
 */
template<typename T>
bool UT2DPoint<T>::operator==(const UT2DPoint &pt) const
{
    if(&pt==this)
    {
        return true;
    }
    else
    {
        return 0==UTMath::Compare(m_tX,pt.m_tX)&&
            0==UTMath::Compare(m_tY,pt.m_tY);
    }
}

/**
 * @brief 检测当前点与指定点是否不同
 * @tparam  T        数据类型 
 * @param   pt       指定点 
 * @return  true     不同 
 * @return  false    相同
 */
template<typename T>
bool UT2DPoint<T>::operator!=(const UT2DPoint &pt) const
{
    return !(*this==pt);
}

/**
 * @brief 将当前点与指定点相加
 * @tparam T     数据类型
 * @param  pt    指定点 
 * @return 返回相加后的结果 
 */
template<typename T>
UT2DPoint<T> UT2DPoint<T>::operator+(const UT2DPoint &pt) const
{
    return UT2DPoint(m_tX+pt.m_tX,m_tY+pt.m_tY);
}

/**
 * @brief 将当前点与指定点自加
 * @tparam  T    数据类型 
 * @param   pt   指定点 
 * @return 返回自身引用 
 */
template<typename T>
UT2DPoint<T> &UT2DPoint<T>::operator+=(const UT2DPoint &pt)
{
    m_tX+=pt.m_tX;
    m_tY+=pt.m_tY;
    return *this;
}

/**
 * @brief 将当前点与指定点相减
 * @tparam  T     数据类型 
 * @param   pt    指定点 
 * @return 返回相减结果
 */
template<typename T>
UT2DPoint<T> UT2DPoint<T>::operator-(const UT2DPoint &pt) const
{
    return UT2DPoint(m_tX-pt.m_tX,m_tY-pt.m_tY);
}

/**
 * @brief 将当前点与指定点自减
 * @tparam  T     数据类型 
 * @param   pt    指定点
 * @return 返回自身引用 
 */
template<typename T>
UT2DPoint<T> &UT2DPoint<T>::operator-=(const UT2DPoint &pt)
{
    m_tX-=pt.m_tX;
    m_tY-=pt.m_tY;
    return *this;
}

/**
 * @brief 设置点的X分量
 * @tparam T  数值类型
 * @param  x  x分量 
 */
template<typename T>
void UT2DPoint<T>::SetX(const T x)
{
    m_tX=x;
}

/**
 * @brief 获取点的X分量
 * @tparam T   数据类型
 * @return 返回点的X分量
 */
template<typename T>
T UT2DPoint<T>::GetX() const
{
    return m_tX;
}

/**
 * @brief 设置点的Y分量
 * @tparam T    数据类型
 * @param  y    y分量 
 */
template<typename T>
void UT2DPoint<T>::SetY(const T y)
{
    m_tY=y;
}

/**
 * @brief 获取点的Y分量
 * @tparam T    数据类型
 * @return 返回点的y分量
 */
template<typename T>
T UT2DPoint<T>::GetY() const
{
    return m_tY;
}

/**
 * @brief 点偏移
 * @tparam T   数据类型
 * @param  x   x方向偏移量
 * @param  y   y方向偏移量 
 */
template<typename T>
void UT2DPoint<T>::Offset(const T x,const T y)
{
    m_tX+=x;
    m_tY+=y;
}

/**
 * @brief 点偏移
 * @tparam T   数值类型
 * @param off  偏移量
 */
template<typename T>
void UT2DPoint<T>::Offset(const UT2DPoint &off)
{
    Offset(off.m_tX,off.m_tY);
}

/**
 * @brief 计算当前点与指定点距离
 * @tparam T   数据类型
 * @param  x   x分量
 * @param  y   y分量 
 * @return 返回计算的距离
 */
template<typename T>
T UT2DPoint<T>::CalculateDistance(const T x,const T y) const
{
    return std::sqrt((m_tX-x)*(m_tX-x)+(m_tY-y)*(m_tY-y));
}

/**
 * @brief 计算当前点与指定点距离
 * @tparam T    数据类型
 * @param  pt   指定点 
 * @return 返回计算的距离
 */
template<typename T>
T UT2DPoint<T>::CalculateDistance(const UT2DPoint &pt) const
{
    return CalculateDistance(pt.m_tX,pt.m_tY);
}

/**
 * @brief 计算当前点与指定点的距离平方
 * @tparam T    数据类型
 * @param  x    x分量
 * @param  y    y分量
 * @param rate  误差率（没有误差时，填1）
 * @return 返回计算的距离平方
 */
template<typename T>
T UT2DPoint<T>::CalculateSquareDistance(const T x,const T y,const T rate/*=static_cast<T>(1)*/)
{
    return (m_tX-x)*(m_tX-x)*rate+(m_tY-y)*(m_tY-y);
}

/**
 * @brief 计算当前点与指定点的距离平方
 * @tparam T     数值类型
 * @param  pt    指定点
 * @param  rate  误差率（没有误差时，填1）
 * @return 返回计算的距离平方
 */
template<typename T>
T UT2DPoint<T>::CalculateSquareDistance(const UT2DPoint &pt,const T rate/*=static_cast<T>(1)*/)
{
    return CalculateSquareDistance(pt.m_tX,pt.m_tY,rate);
}

/**
 * @brief 二维点常用类型定义
 */
using D2DPNT=UT2DPoint<double>;
using F2DPNT=UT2DPoint<float>;
using I2DPNT=UT2DPoint<int32_t>;
using L2DPNT=UT2DPoint<int64_t>;
using MI2DPOINT=I2DPNT;
using MF2DPOINT=F2DPNT;
using MD2DPOINT=D2DPNT;
using MF2DLONLAT=F2DPNT;

END_SPACE_LANGE_VDR

#endif // !UT_POINT_H